/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = frct_ssl_mng.c                                     */
/*  NOTE      = 接收共享内存中ssl的信息,添加到ct队列里处理         */
/*  DATE      = 2016/02/15 by guojq                                */
/*******************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <errno.h>

#include "frcomm.h"
#include "frlog.h"
#include "frame.h"
#include "frct_mng.h"
#include "frstat_pkg.h"

#include "frdssl.h"
#include "frshm_pool.h"
#include "frsem.h"
#include "frshm_stat.h"
#include "frame_params.h"

#ifndef FRSSL_SHM
    #include <zmq.h>
#endif
FR_STATIC int g_i_srv_timeout = 3000;

/*******************************************************************************
*  FUNC     :  把ssl解密信息加入ct
*  ARGS     :  p_option(数据块头信息)
*           :  p_decode(解密内容)
*  RTN      :  FR_SUCC (success)
*           :  FR_FAIL (failed)
*  NOTE     :
*******************************************************************************/
FR_STATIC int __frdssl_ct_add(ssl_option *p_option, char *p_decode, int i_decode_len)
{
    struct timeval st_timeval_pkg;
    char *p_src_mac = "\0\0\0\0\0\0";
    char *p_dst_mac = "\0\0\0\0\0\0";
    
    st_timeval_pkg = p_option->st_ts;
    
    switch (p_option->i_conn_type)
    {
        case SSL_TYPE_SYN:
        {
            frstat_pkg_add_frame_syn(1);
            //增加连接
            frct_add(p_src_mac, p_dst_mac, IPPROTO_TCP
                    , p_option->st_ipinfo.i_sip, p_option->st_ipinfo.i_sport
                    , p_option->st_ipinfo.i_dip, p_option->st_ipinfo.i_dport
                    , FR_YES, FRANALYZ_CMD_SYN
                    , FR_NO, APM_CONNECT_SYN_SENT, NULL, 0, st_timeval_pkg, 0, 1);
            break;
        }
        case SSL_TYPE_FIN:
        {
            frstat_pkg_add_frame_fin(1);
            
            frct_del(IPPROTO_TCP
                    , p_option->st_ipinfo.i_sip, p_option->st_ipinfo.i_sport
                    , p_option->st_ipinfo.i_dip, p_option->st_ipinfo.i_dport
                    , FRANALYZ_CMD_FIN, st_timeval_pkg);
            break;
        }
        case SSL_TYPE_DATA:
        {
            frstat_pkg_add_frame_tcp(1);
            
            frct_add(p_src_mac, p_dst_mac, IPPROTO_TCP
                    , p_option->st_ipinfo.i_sip, p_option->st_ipinfo.i_sport
                    , p_option->st_ipinfo.i_dip, p_option->st_ipinfo.i_dport
                    , FR_YES, FRANALYZ_CMD_DATA
                    , FR_NO, APM_CONNECT_ESTABLISHED
                    , p_decode, i_decode_len, st_timeval_pkg, 0, 1);
            break;
        }
        default:
            return FR_FAIL;
    }
    
    return FR_SUCC;
}

#ifndef FRSSL_SHM
static void *__init_socket(void *context, char *p_addr)
{
    void *socket = NULL;
    int i_timeout = g_i_srv_timeout;

    socket = zmq_socket(context, ZMQ_PULL);
    if (socket == NULL)
    {
        frwarn("zmq_socket failed, errno=[%s]", strerror(errno));
        return NULL;
    }
    if(zmq_setsockopt(socket, ZMQ_RCVTIMEO, &i_timeout, sizeof(i_timeout)) < 0)
    {
        frwarn("zmq_setsockopt failed, errno=[%s]", strerror(errno));
        zmq_close(socket);
        return NULL;
    }
    if(zmq_setsockopt(socket, ZMQ_LINGER, &i_timeout, sizeof(i_timeout)) < 0)
    {
        frwarn("zmq_setsockopt failed, errno=[%s]", strerror(errno));
        zmq_close(socket);
        return NULL;
    }
    
    if (zmq_bind(socket, p_addr) != 0)
    {
        frwarn("zmq_bind failed, errno=[%s]", strerror(errno));
        zmq_close(socket);
        return NULL;
    }
    
    return socket;
}
#endif

void *frct_ssl_mng(void *arg)
{
    int i_read = 0;
    char *p_read = NULL;
    
#ifdef FRSSL_SHM
    int i_shmid = 0, i_semid = 0;
    i_shmid = frshm_pool_get(SHM_FILE);
    if (i_shmid < 0)
    {
        FRLOG_ERROR_DETAIL("frshm_pool_get error[%s]", strerror(errno));
        goto err;
    }
    
    i_semid = frsem_get(SEM_FILE);
    if (i_semid < 0)
    {
        FRLOG_ERROR_DETAIL("frsem_get error[%s]", strerror(errno));
        goto err;
    }
    
    if (frshm_stat_get() != FR_SUCC)
    {
        FRLOG_ERROR("frshm_stat_get error [%s]", strerror(errno));
        goto err;
    }
#else
    void *socket = 0;
    void *context = zmq_init(1);
    int i_read_max = 102400;
    
    if (context == NULL)
    {
        FRLOG_ERROR_DETAIL("zmq_ctx_new faild\n");
        return (void*)NULL;
    }
    socket = __init_socket(context, st_apm_params.arr_dssl_zmq_connect);
    if (socket == NULL)
    {
        FRLOG_ERROR_DETAIL("connect to server faild\n");
        zmq_term(context);
        return (void*)NULL;
    }
    p_read = (char *)frmalloc(i_read_max);
    if (p_read == NULL)
    {
        if (socket)
            zmq_close(socket);
        if (context)
            zmq_term(context);
        return (void*)NULL;
    }
#endif
    
    while (g_i_flag_run)
    {
        ssl_decode *p_st_decode = NULL;
    
#ifdef FRSSL_SHM
        frsemaphore_lock(i_semid);
        
        i_read = frshm_pool_read(i_shmid, (void **)&p_read);
        if (i_read < 0)
        {
            //读取共享内存错误
            FRLOG_ERROR_DETAIL("frshm_pool_read error[%s]", strerror(errno));
            frsemaphore_unlock(i_semid);
            return (void*)NULL;
        }
        else if (i_read == 0)
        {
            //共享内存里没有数据
            frsemaphore_unlock(i_semid);
            usleep(10000);
            continue;
        }
#else
        i_read = zmq_recv(socket, p_read, i_read_max, 0);
        if (i_read <= 0)
        {
            usleep(10000);
            continue;
        }
#endif
        
        p_st_decode = (ssl_decode *)p_read;
        //检查数据内容
        if (i_read != p_st_decode->i_decode_len + sizeof(ssl_decode))
        {
            frwarn("share memory data error");
#ifdef FRSSL_SHM
            frsemaphore_unlock(i_semid);
#endif
            usleep(10000);
            continue;
        }
        __frdssl_ct_add(&p_st_decode->st_option, p_st_decode->p_decode, p_st_decode->i_decode_len);

#ifdef FRSSL_SHM
        if (p_read)
        {
            frfree(p_read);
            p_read = NULL;
        }
        frsemaphore_unlock(i_semid);
#endif
    }
   
#ifndef FRSSL_SHM 
    if (socket)
        zmq_close(socket);
    if (context)
        zmq_term(context);
    if (p_read)
        frfree(p_read);
#endif

    return (void*)NULL;
err:
    return (void*)NULL;
}
